import type { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
import { MessageBox } from 'element-ui'
// 引入进度条
import nprogress from 'nprogress'
// 引入进度条样式
import 'nprogress/nprogress.css'
// 引入vuex
import store from '@/store'
import VueRouter from 'vue-router'
import vue from 'vue'
// @ts-ignore
// 创建实例时设置配置的默认值
const service: AxiosInstance = axios.create({
  baseURL: '/api',
  timeout: 5000,
  // 携带cookie
  withCredentials: true,
})

// 添加请求拦截器
service.interceptors.request.use(
  (config: AxiosRequestConfig) => {
    // 在发送请求之前做些什么
    nprogress.start()
    // 登录后的token
    const token = store.state.user.token
    if (token && config.headers) config.headers.Authorization = `Bearer ${token}`
    return config
  },
  // 对请求错误做些什么
  (error: AxiosError) => {
    return Promise.reject(error)
  },
)

// 添加响应拦截器
service.interceptors.response.use(
  (response: AxiosResponse) => {
    nprogress.done()
    const { code, msg } = response.data
    // 根据自定义错误码判断请求是否成功
    if (code === 200) {
      // 将组件用的数据返回
      return response.data
    } else {
      return Promise.reject(new Error(msg))
    }
  },
  (error: AxiosError) => {
    nprogress.done()
    // 处理 HTTP 网络错误
    let message = ''
    // HTTP 状态码
    const status = error.response?.status
    switch (status) {
      case 401:
        message = '401-token 失效，请重新登录'
        store.commit('user/CLEAR')
        MessageBox.alert('登录已过期，是否重新登录', '提示', {
          confirmButtonText: '确定',
          callback: action => {
            if (action == 'confirm') VueRouter.prototype.push('/login')
          },
        })
        break
      case 403:
        message = '403-拒绝访问'
        break
      case 404:
        message = '404-请求地址错误'
        break
      case 500:
        message = '500-服务器故障'
        break
      default:
        message = '网络连接故障'
    }
    return Promise.reject(error)
  },
)

/* 导出封装的请求方法 */
export const http = {
  get<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
    return service.get(url, config)
  },
  post<T = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig): Promise<T> {
    return service.post(url, data, config)
  },
  put<T = any, D = any>(url: string, data?: D, config?: AxiosRequestConfig): Promise<T> {
    return service.put(url, data, config)
  },
  delete<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
    return service.delete(url, config)
  },
}
